package com.bonc.hbase.api.ctrl;


import java.io.IOException;

import javax.servlet.http.HttpServletRequest;

import org.apache.hadoop.hbase.client.Result;
import org.apache.hadoop.hbase.util.Bytes;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

import com.alibaba.fastjson.JSONObject;
import com.bonc.hbase.api.client.HbaseConvertUtil;
import com.bonc.hbase.api.client.HbaseOperateClient;
import com.bonc.hbase.api.constant.BaseConstant;
import com.bonc.hbase.api.entity.JsonResult;
import com.bonc.hbase.api.util.ValidateRequestUtil;


/**
 * 距离计算接口
 * 
 * @author caiqiang
 * @version 2016年8月3日
 * @see DistanceApiController
 * @since
 */
@RestController
@RequestMapping("/api/v1")
public class DistanceApiController {

    /**
     * HBase 数据操作客户端
     */
    @Autowired
    private HbaseOperateClient hbaseOperateClient;

    /**
     * 日志对象
     */
    private static final Logger LOG = LoggerFactory.getLogger(DistanceApiController.class);

    /**
     * Description:计算距离
     * 
     * @param phone
     * @param longitude
     * @param latitude
     * @param request
     * @return Object
     * @see
     */
    @RequestMapping(value = {"/distance"}, method = RequestMethod.GET)
    public Object getDistance(String phone, String longitude, String latitude,
                              HttpServletRequest request) {

        if (!ValidateRequestUtil.validate(request) || StringUtils.isEmpty(phone)
            || StringUtils.isEmpty(longitude) || StringUtils.isEmpty(latitude)) {
            return new JsonResult(BaseConstant.CODE_TOKEN_ILLEGAL, BaseConstant.MSG_TOKEN_ILLEGAL);
        }

        byte[] rowkey = convertToPhoneByte(phone);
        Result result = new Result();
        try {
            result = hbaseOperateClient.getResult(rowkey, "current_position");
        }
        catch (IOException e) {
            LOG.error(e.getMessage());
            return new JsonResult(BaseConstant.CODE_ERROR, BaseConstant.MSG_ERROR);
        }
        if (result == null || result.isEmpty()) {
            return new JsonResult(BaseConstant.CODE_DATA_NONEXIST, BaseConstant.MSG_DATA_NONEXIST);
        }
        String[] strValueArray = HbaseConvertUtil.getListValue(new String(result.getValue(
            Bytes.toBytes("f"), Bytes.toBytes("q"))));
        if (strValueArray == null || strValueArray.length <= 0) {
            return new JsonResult(BaseConstant.CODE_DATA_NONEXIST, BaseConstant.MSG_DATA_NONEXIST);
        }
        String longitudeFromDB = strValueArray[0];
        String latitudeFromDB = strValueArray[1];
        double distance = evaluateDistance(latitudeFromDB, longitudeFromDB, latitude, longitude);
        JSONObject returnObj = new JSONObject();
        returnObj.put("distance", distance);
        return new JsonResult(returnObj);
    }

    /**
     * Description:创建rowkey
     * 
     * @param phone
     * @return byte[]
     * @see
     */
    private byte[] convertToPhoneByte(String phone) {
        byte[] phoneId = Bytes.copy(Bytes.toBytes(Long.parseLong(phone)), 3, 5);
        byte[] deviceNumberHash = Bytes.toBytes((short)(phone.hashCode() & 0x7fff));
        byte[] rowkey = Bytes.add(deviceNumberHash, phoneId);

        return rowkey;

    }

    private double evaluateDistance(String lat1Str, String lng1Str, String lat2Str, String lng2Str) {

        double lat1 = Double.parseDouble(lat1Str);
        double long1 = Double.parseDouble(lng1Str);
        double lat2 = Double.parseDouble(lat2Str);
        double long2 = Double.parseDouble(lng2Str);

        double a;
        double b;
        double r;

        r = 6378137;

        lat1 = lat1 * Math.PI / 180.0;
        lat2 = lat2 * Math.PI / 180.0;
        a = lat1 - lat2;
        b = (long1 - long2) * Math.PI / 180.0;
        double d;
        double sa2;
        double sb2;
        sa2 = Math.sin(a / 2.0);
        sb2 = Math.sin(b / 2.0);
        d = 2 * r * Math.asin(Math.sqrt(sa2 * sa2 + Math.cos(lat1) * Math.cos(lat2) * sb2 * sb2));

        return d;
    }
}
